// Jack Chua
// Georgia Tech HPC Class Project - MPI

#include "mpi-allr.h"
#include <string.h>

int
main (int ac, char *av[])
{
  //check to see if an array size has been passed
  if (ac != 4) { printf("usage: %s arraysize tasknum op\n", av[0]); return(0); }

  //get operation
  MPI_Op op;
  if (strcmp(av[3],"MPI_SUM")==0)      { op = MPI_SUM; }
  else if (strcmp(av[3],"MPI_MIN")==0) { op = MPI_MIN; }
  else if (strcmp(av[3],"MPI_MAX")==0) { op = MPI_MAX; }
  else                                  { op = MPI_SUM; } //default to sum

  //init vars
  int i;
  int rank = -1;
  int count = 100;

#ifdef DEBUG
  int fnderr = 0;
#endif

  const int maxsize = atoi(av[1]);
  double start, stop;
  double sbuf[maxsize];
  double rbuf[maxsize];
  double tbuf[maxsize]; //buffer for results from MPI's implementation

  //init mpi
  MPI_Init (&ac, &av);
  MPI_Comm_rank (MPI_COMM_WORLD, &rank);

  //populate send buffer
  for (i = 0; i < maxsize; i++)
    {
      sbuf[i] = (i + 1) * 1.0;
    }

  //run our implementation
  start = MPI_Wtime ();
  for (i = 0; i < count; i++)
    {
      gthpc_Allreduce (sbuf, rbuf, maxsize, op, MPI_COMM_WORLD);
    }
  stop = MPI_Wtime ();
  
  //run MPI's implementation
  for (i=0; i < count; i++)
  {
      MPI_Allreduce(sbuf, tbuf, maxsize, MPI_DOUBLE, op, MPI_COMM_WORLD);
  }

#ifdef DEBUG
  for (i=0; i < maxsize; i++)
  {
      printf("rbuf[%d]=%lf, tbuf[%d]=%lf\n", i, rbuf[i], i, tbuf[i]);
      if (*(tbuf+i) != *(rbuf+i)) { fnderr++; }
  }
  printf("Errors for Node %d: %d\n", rank, fnderr);
#endif

  //print timing stats
  if (rank == 0)
    {
      /*
      printf ("Size = %d\n"
              "Runtime = %g\n"
     	      "Calls = %d\n"
     	      "Time per call = %g us\n",
     	      maxsize, stop - start, count, 1e6 * (stop - start) / count);
      */
      printf("%d, %d, %g, %d, %g\n", atoi(av[2]), maxsize, stop-start, count, 1e6*(stop-start)/count);
    }

  MPI_Finalize ();
  return 0;
}
